Skip to content

feat(tenant-manager): add CreateTenant client method#555

Merged
fredcamaral merged 3 commits into
developfrom
feat/tm-client-create-tenant-v6
Jul 21, 2026
Merged

feat(tenant-manager): add CreateTenant client method#555
fredcamaral merged 3 commits into
developfrom
feat/tm-client-create-tenant-v6

Conversation

@fredcamaral

Copy link
Copy Markdown
Member

What

Adds a CreateTenant method to the Tenant Manager client (commons/tenant-manager/client) for provisioning a tenant via POST /v1/tenants.

  • Idempotent by tenant identity. The Tenant Manager returns the existing tenant with 200 OK on a repeat create, so the method treats both 200 and 201 as success and unmarshals the returned tenant record.
  • Mirrors the read methods' transport contract: circuit-breaker gating, a size-limited response body (maxResponseBodySize), and trace-context injection (InjectHTTPContext).
  • RBAC-gated write. Sends the service-account bearer token from a configurable TokenProvider (WithBearerTokenProvider) plus the always-required X-API-Key. When no provider is configured, no Authorization header is sent.
  • Status mapping: a 5xx is a service failure that feeds the circuit breaker; any 4xx is a valid round-trip that resets the failure counter. 409 maps to the typed core.ErrTenantConflict; other 4xx surface the truncated response body for diagnosis.

Public API (CreateTenant, CreateTenantRequest/CreateTenantResponse, TenantOwner, TokenProvider, WithBearerTokenProvider) is preserved for downstream consumers.

Why

The matcher standalone-SaaS control plane provisions tenants through this client, so the write path needs a first-class CreateTenant alongside the existing read methods (GetTenantConfig, GetActiveTenantsByService, GetTenantMetadata).

Observability port note

The method was authored against matcher's module graph, which imports the unversioned github.com/LerianStudio/lib-observability{,/log,/tracing}. lib-commons /v6 instead depends on github.com/LerianStudio/lib-observability/v2 (go.mod), which is exactly what the sibling client files (client.go, metadata.go) already use. This PR ports the three import paths to /v2 — same observability.NewTrackingFromContext, libLog.*, and libOpentelemetry.* surface as the siblings. No new module dependency is added.

Tests

go test -tags=unit ./commons/tenant-manager/client/... — 121 pass (10 CreateTenant cases: success, idempotent existing-tenant, bearer/no-bearer, bearer-provider error, 5xx breaker trip, malformed body, network error, 409 typed sentinel, generic 4xx body passthrough, 4xx not-breaker). go build ./commons/tenant-manager/... and go vet clean.

https://claude.ai/code/session_019CPR8BaUFL4TuPVos9DGds

Add a CreateTenant method to the Tenant Manager client for provisioning tenants via POST /v1/tenants. It mirrors the read methods' transport contract (circuit-breaker gating, size-limited response body, trace-context injection) and is idempotent by tenant identity: a repeat create returns the existing tenant with 200 OK, so both 200 and 201 map to success. A 5xx feeds the circuit breaker; a 4xx is a valid round-trip (409 maps to the typed ErrTenantConflict). The RBAC-gated write carries the service-account bearer token plus X-API-Key.

The matcher standalone-SaaS control plane consumes this via the client to provision tenants.

Observability is ported to the lib-observability/v2 packages the sibling client files already use (log/tracing/NewTrackingFromContext), replacing the matcher-era unversioned lib-observability imports; no new module dependency is added.

X-Lerian-Ref: 0x1
Claude-Session: https://claude.ai/code/session_019CPR8BaUFL4TuPVos9DGds
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6328f234-5f14-478c-9e12-50d06a96079d

📥 Commits

Reviewing files that changed from the base of the PR and between 2065bae and 4158946.

📒 Files selected for processing (4)
  • commons/tenant-manager/client/coverage_boost_test.go
  • commons/tenant-manager/client/create_tenant.go
  • commons/tenant-manager/client/create_tenant_test.go
  • commons/tenant-manager/client/extra_test.go

📝 Walkthrough

Walkthrough

Adds a Tenant Manager tenant-creation client with optional bearer authentication, typed request and response models, tracing, circuit-breaker handling, conflict errors, fixed response-body truncation, and HTTP behavior tests.

Changes

Tenant creation client

Layer / File(s) Summary
Client authentication and contracts
commons/tenant-manager/client/create_tenant.go, commons/tenant-manager/client/client.go, commons/tenant-manager/client/metadata.go
Adds bearer-token configuration and tenant creation request/response types, and updates security suppression directives for validated URLs.
Create flow and status handling
commons/tenant-manager/client/create_tenant.go, commons/tenant-manager/core/errors.go
Implements JSON POST /v1/tenants requests with optional bearer authorization, tracing, response limits, circuit-breaker accounting, HTTP 200/201 success handling, typed 409 conflicts, and 4xx/5xx errors.
Tenant creation behavior coverage
commons/tenant-manager/client/create_tenant_test.go
Tests successful and idempotent creation, authentication variants, provider and network failures, malformed responses, conflict handling, truncated error bodies, and circuit-breaker behavior.
Fixed response-body truncation
commons/tenant-manager/client/client.go, commons/tenant-manager/client/metadata.go, commons/tenant-manager/client/*_test.go
Updates truncateBody to use a fixed 512-byte limit and adjusts logging call sites and tests to the new signature.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant CreateTenant
  participant TokenProvider
  participant TenantManagerAPI
  Caller->>CreateTenant: CreateTenant(request)
  CreateTenant->>TokenProvider: Request bearer token
  TokenProvider-->>CreateTenant: Token or error
  CreateTenant->>TenantManagerAPI: POST /v1/tenants
  TenantManagerAPI-->>CreateTenant: Tenant response or HTTP error
  CreateTenant-->>Caller: Response or typed error
Loading
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/tm-client-create-tenant-v6

Comment @coderabbitai help to get the list of available commands.

@lerian-studio lerian-studio added size/M PR changes 200–499 lines tenant-manager Tenant manager tests Unit, integration and end-to-end tests labels Jul 21, 2026
@lerian-studio

lerian-studio commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🔒 Security Scan Results — lib-commons

✅ PR Mergeable — no blocking findings

Stage Status Blocking?
Filesystem Scan ✅ Clean
Docker Image Scan ➖ Skipped
Docker Hub Health Score ➖ Skipped
Pre-release Version Check ✅ Clean

Trivy

Filesystem Scan

✅ No vulnerabilities or secrets found.


Pre-release Version Check

✅ No unstable version pins found.


🔍 View full scan logs

@lerian-studio

lerian-studio commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🔍 PR Validation Summary

✅ PR Mergeable — no blocking failures

Check Status Blocking
Source Branch ✅ success yes
PR Title ✅ success yes
PR Description ✅ success yes
PR Size ✅ success no
Auto Labels ✅ success no
PR Metadata ✅ success no

🔍 View workflow run

@lerian-studio

lerian-studio commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

📊 Unit Test Coverage Report: app

Metric Value
Overall Coverage 87.3% ✅ PASS
Threshold 80%

Coverage by Package

Package Coverage
github.com/LerianStudio/lib-commons/v6/commons/backoff 91.1%
github.com/LerianStudio/lib-commons/v6/commons/certificate 88.8%
github.com/LerianStudio/lib-commons/v6/commons/circuitbreaker 86.8%
github.com/LerianStudio/lib-commons/v6/commons/cron 94.2%
github.com/LerianStudio/lib-commons/v6/commons/crypto 95.6%
github.com/LerianStudio/lib-commons/v6/commons/dlq 81.0%
github.com/LerianStudio/lib-commons/v6/commons/errgroup 86.1%
github.com/LerianStudio/lib-commons/v6/commons/events 100.0%
github.com/LerianStudio/lib-commons/v6/commons/internal/nilcheck 100.0%
github.com/LerianStudio/lib-commons/v6/commons/jwt 89.4%
github.com/LerianStudio/lib-commons/v6/commons/license 96.9%
github.com/LerianStudio/lib-commons/v6/commons/mongo 89.0%
github.com/LerianStudio/lib-commons/v6/commons/net/http/idempotency 87.9%
github.com/LerianStudio/lib-commons/v6/commons/net/http/openapi 98.4%
github.com/LerianStudio/lib-commons/v6/commons/net/http/problem 100.0%
github.com/LerianStudio/lib-commons/v6/commons/net/http/ratelimit 92.3%
github.com/LerianStudio/lib-commons/v6/commons/net/http 96.2%
github.com/LerianStudio/lib-commons/v6/commons/outbox 92.2%
github.com/LerianStudio/lib-commons/v6/commons/pointers 100.0%
github.com/LerianStudio/lib-commons/v6/commons/postgres 87.7%
github.com/LerianStudio/lib-commons/v6/commons/rabbitmq 89.2%
github.com/LerianStudio/lib-commons/v6/commons/redis 89.6%
github.com/LerianStudio/lib-commons/v6/commons/safe 99.6%
github.com/LerianStudio/lib-commons/v6/commons/secretsmanager 99.4%
github.com/LerianStudio/lib-commons/v6/commons/security/ssrf 95.9%
github.com/LerianStudio/lib-commons/v6/commons/security 100.0%
github.com/LerianStudio/lib-commons/v6/commons/server 87.3%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/cache 97.9%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/client 93.2%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/consumer 87.9%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/core 98.5%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/event 96.5%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/internal/eviction 100.0%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/log 100.0%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/middleware 93.8%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/mongo 76.3%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/postgres 84.9%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/rabbitmq 83.3%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/redis 95.8%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/s3 89.3%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/tenantcache 98.6%
github.com/LerianStudio/lib-commons/v6/commons/tenant-manager/valkey 100.0%
github.com/LerianStudio/lib-commons/v6/commons/transaction 95.1%
github.com/LerianStudio/lib-commons/v6/commons/webhook 93.2%
github.com/LerianStudio/lib-commons/v6/commons 95.2%

Generated by Go PR Analysis workflow

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@commons/tenant-manager/client/create_tenant.go`:
- Line 77: Update handleCreateTenantStatus to accept the request-scoped logger
created by observability.NewTrackingFromContext(ctx), and replace all three
c.logger.Log calls in its branches with that logger. Pass the tracking logger
from CreateTenant while preserving the existing status-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c718e737-fd81-4909-8f29-e0fa3af177a9

📥 Commits

Reviewing files that changed from the base of the PR and between 4e338b9 and 5760ee3.

📒 Files selected for processing (5)
  • commons/tenant-manager/client/client.go
  • commons/tenant-manager/client/create_tenant.go
  • commons/tenant-manager/client/create_tenant_test.go
  • commons/tenant-manager/client/metadata.go
  • commons/tenant-manager/core/errors.go

Comment thread commons/tenant-manager/client/create_tenant.go
Address PR #555 review + lint gate:

- handleCreateTenantStatus now receives the request-scoped logger
  derived in CreateTenant (trace-correlated) instead of the static
  client logger (CodeRabbit review).
- truncateBody drops the maxLen parameter (always 512, unparam);
  limit is a local const.

X-Lerian-Ref: 0x1
Claude-Session: https://claude.ai/code/session_019CPR8BaUFL4TuPVos9DGds

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@commons/tenant-manager/client/coverage_boost_test.go`:
- Around line 183-185: The truncation tests use weak assertions that do not
verify the exact output. In commons/tenant-manager/client/coverage_boost_test.go
lines 183-185, assert the result equals the first 512 bytes of body followed by
"...(truncated)", removing the space from the suffix literal. Apply the same
exact 512-byte prefix and "...(truncated)" suffix assertion in
commons/tenant-manager/client/extra_test.go lines 217-225.

In `@commons/tenant-manager/client/create_tenant.go`:
- Around line 163-192: Update handleCreateTenantStatus so the business-rejection
handling currently in the default branch applies only to 4xx status codes. Add a
separate branch for unexpected non-4xx, non-5xx statuses such as 202 and 3xx,
preserving appropriate failure/error handling without resetting the circuit
breaker or classifying them as tenant rejections.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b63e0d40-19c2-4d93-b40a-3a34071953dc

📥 Commits

Reviewing files that changed from the base of the PR and between 5760ee3 and 2065bae.

📒 Files selected for processing (5)
  • commons/tenant-manager/client/client.go
  • commons/tenant-manager/client/coverage_boost_test.go
  • commons/tenant-manager/client/create_tenant.go
  • commons/tenant-manager/client/extra_test.go
  • commons/tenant-manager/client/metadata.go

Comment thread commons/tenant-manager/client/coverage_boost_test.go Outdated
Comment thread commons/tenant-manager/client/create_tenant.go
CodeRabbit round 2:

- handleCreateTenantStatus: business-rejection branch now explicit
  4xx; unexpected statuses (202, 3xx) log an error without touching
  circuit-breaker counters, mirroring handleGetTenantConfigStatus.
  New test proves a 202 does not reset preloaded breaker failures.
- Truncation tests assert exact body[:512] + "...(truncated)" output.

X-Lerian-Ref: 0x1
Claude-Session: https://claude.ai/code/session_019CPR8BaUFL4TuPVos9DGds
@lerian-studio lerian-studio added size/L PR changes 500–999 lines and removed size/M PR changes 200–499 lines labels Jul 21, 2026
@fredcamaral
fredcamaral merged commit 7570331 into develop Jul 21, 2026
22 checks passed
@github-actions
github-actions Bot deleted the feat/tm-client-create-tenant-v6 branch July 21, 2026 22:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L PR changes 500–999 lines tenant-manager Tenant manager tests Unit, integration and end-to-end tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants